package per.ethan.springboot.example.service.impl;

import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import per.ethan.springboot.example.entity.ScheduleJob;
import per.ethan.springboot.example.service.ScheduleService;

/**
 * @author Ethan
 * @date 2020/06/07 15:44
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ScheduleServiceImpl implements ScheduleService {

    private final Scheduler scheduler;

    @Override
    public void addJob(ScheduleJob scheduleJob) {
        try {
            JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroupName());
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);

            // 判断任务是否存在，如果任务不存在就添加任务，如果任务存在就更新任务
            if (null == jobDetail) {
                 jobDetail = JobBuilder.newJob(scheduleJob.getJobClass())
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroupName())
                        .build();

                if (CollUtil.isNotEmpty(scheduleJob.getJobData())) {
                    jobDetail.getJobDataMap().putAll(scheduleJob.getJobData());
                }

                /*withMisfireHandlingInstructionDoNothing
                ——不触发立即执行
                ——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行

                withMisfireHandlingInstructionIgnoreMisfires
                ——以错过的第一个频率时间立刻开始执行
                ——重做错过的所有频率周期后
                ——当下一次触发频率发生时间大于当前时间后，再按照正常的Cron频率依次执行

                withMisfireHandlingInstructionFireAndProceed
                ——以当前时间为触发频率立刻触发一次执行
                ——然后按照Cron频率依次执行*/
                CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                        .withMisfireHandlingInstructionDoNothing();

                CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getTriggerName(), scheduleJob.getTriggerGroupName())
                        .withSchedule(cronScheduleBuilder)
                        .build();

                scheduler.scheduleJob(jobDetail, cronTrigger);
            } else {
                this.updateJob(scheduleJob);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void deleteJob(ScheduleJob scheduleJob) {
        try {
            JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroupName());
            scheduler.pauseJob(jobKey);
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void updateJob(ScheduleJob scheduleJob) {
        this.deleteJob(scheduleJob);
        this.addJob(scheduleJob);
    }

    @Override
    public void pauseJob(ScheduleJob scheduleJob) {
        try {
            JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroupName());
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void pauseAllJob() {
        try {
            scheduler.pauseAll();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void resumeJob(ScheduleJob scheduleJob) {
        try {
            JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroupName());
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void resumeAllJob() {
        try {
            scheduler.resumeAll();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void runJobNow(ScheduleJob scheduleJob) {
        try {
            JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroupName());
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

}
